package com.tyrone.concurrent.framework;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

/**
 * Fork/Join 框架
 *
 * Fork/Join 的实现需要解决以下两个问题：
 * ① 如何Fork,也就是如何分割任务？
 * ② 如何Join，怎么将子任务合在一起？
 * Fork/Join框架通过 ForkJoinTask类和 ForkJoinPool解决以上的两个问题
 *
 * ForkJoinTask类有两个实现类：
 * 1.RecursiveAction 无返回值
 * 2.RecursiveTask 有返回值
 *
 * ForkJoinPool主要由ForkJoinTask数组和ForkJoinWorkerThread数组组成：
 * ForkJoinTask数组主要用来存放Fork的子任务，并且将存放的子任务交给ForkJoinPool
 * ForkJoinPool再调用ForkJoinWorkerThread数组去执行这些任务。
 *
 * ForkJoinTask 的 fork()方法的实现：
 * ①当调用fork()时候，会调用ForkJoinWorkerThread（工作者线程）的 pushTask()方法
 * 注意：fork()是个异步方法
 * ②pushTask()将任务异步提交到ForkJoinPool的ForkJoinTask数组中，然后调用
 * ForkJoinPool.signalWorker()方法来唤醒一个工作者线程来执行任务。
 *
 * 所以说，ForkJoinWorkerThread类 主要干了以下的事情：
 * ①将子任务推送到ForkJoinPool中的ForkJoinTask数组中
 * ②执行ForkJoinTask数组中的任务
 *
 * ForkJoinTask 的 join()方法的实现：
 * join()的主要作用就是阻塞当前线程并等待 直到获取结果
 * join()会调用doJoin()方法来的得到当前任务的状态来返回什么的结果，主要的状态有：
 * NORMAL(已完成)  :直接返回任务结果
 * CANCELLED(被取消)   :直接抛出CancellationException
 * SIGNAL(信号)   :
 * EXCEPTIONAL(出现异常)    :抛出相对的异常
 *
 *
 * @author Tyrone
 * @date 2021/12/22 12:39
 */
public class CountTask extends RecursiveTask<Integer> {

    private static final int THRESHOLD = 2; //阈值

    private int start;
    private int end;


    public CountTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        int sum = 0;
        boolean canCompute = (end - start) <= THRESHOLD;
        if (canCompute) {
            for (int i = start; i <= end; i++) {
                sum += i;
            }
        } else {
            int middle = (start + end) / 2;
            CountTask leftTask = new CountTask(start, middle);
            CountTask rightTask = new CountTask(middle+1, end);
            //执行子任务
            leftTask.fork();  //相当于执行leftTask.compute(start,middle)
            rightTask.fork();
            //获取子任务的结果
            Integer leftResult = leftTask.join();
            Integer rightResult = rightTask.join();
            sum = leftResult + rightResult;
        }
       // int a = 1/0;
        return sum;
    }

    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        CountTask task = new CountTask(1,4);
        Future<Integer> result = forkJoinPool.submit(task);
//        if (task.isCompletedAbnormally()){
//            Throwable exception = task.getException();
//            System.out.println(exception.getMessage());
//        }
        try{
            System.out.println(result.get());
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}
